home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / boot / netBoot / asyncbuf.h < prev    next >
Encoding:
C/C++ Source or Header  |  1988-05-13  |  7.0 KB  |  204 lines

  1.  
  2. /*    @(#)asyncbuf.h 1.1 86/09/27 SMI    */
  3.  
  4. /*
  5.  * Copyright (c) 1986 by Sun Microsystems, Inc.
  6.  */
  7.  
  8. /* These definitions and structures permit the creation of 
  9.  * asynchronously accessed buffers in shared memory.  The
  10.  * writer and the reader of the buffer have separate pointers
  11.  * into it, which they themselves manage.
  12.  *
  13.  * -------------------------------------- John Gilmore, 21Apr82
  14.  *
  15.  * Generalized to buffers of any type...JCGilmore 21May82
  16.  *
  17.  * Example:
  18.  *    DEFBUF (bytebuf, char, 300);
  19.  *    struct bytebuf OurBuffer[1];
  20.  *    ...
  21.  *    initbuf (OurBuffer, 300);
  22.  *    ...
  23.  *    OurChar = getchar();
  24.  *    bput (OurBuffer, OurChar);
  25.  *
  26.  * Note that OurBuffer is declared as an array of one bytebuf.  This is
  27.  * so that "OurBuffer" will act as a pointer constant.  The macros are set up to
  28.  * take pointers rather than structure names for reasons that will be
  29.  * obvious two paragraphs down.
  30.  *
  31.  * This means that if you reference the members of OurBuffer, you must
  32.  * say  OurBuffer->getptr  or  (*OurBuffer).getptr  or  OurBuffer[0].getptr
  33.  * instead of  OurBuffer.getptr .
  34.  *
  35.  * Meanwhile somebody else with access to the same memory locations is
  36.  * quietly doing
  37.  *    DEFBUF (bytebuf, char, 300);
  38.  *    struct bytebuf *TheirBuffer = GetTheirBufferAddr();
  39.  *     ...
  40.  *    if (bgetp (TheirBuffer)) bget (TheirBuffer, TheirChar);
  41.  *    ...
  42.  *
  43.  * It is also possible to pull out multiple datums at once.  The construct
  44.  *    bgets (TheirBuffer, addr, count);
  45.  * will return the address of a series of datums, and how many there are.
  46.  * This count might be zero if no data is waiting.  If the buffer has 
  47.  * wrapped around from end to start, the first call will return a count
  48.  * from the "get" pointer thru the end of the buffer.  After these datums
  49.  * are accepted (with baccs), the next bgets will return an addr and count
  50.  * that describes the 2nd half of the data.  NOTE that data returned by
  51.  * bgets is still sitting in the buffer area.  It MUST be accepted by
  52.  * calling
  53.  *    baccs (TheirBuffer, count);
  54.  * before attempting to do another bget, bgetp, or bgets.  It can be accepted
  55.  * in chunks, tho, as in:
  56.  *    while (count--) {do_something (addr++); baccs(TheirBuffer, 1);}
  57.  *
  58.  * bgets declares one register pointer variable in an internal block.  This
  59.  * will cause one more register to be saved and restored on procedure entry
  60.  * and exit.  If no register is available, I believe the compiler will just
  61.  * use a temp.
  62.  *
  63.  * OVERRUN HANDLING: Overrun is set by bputo() when it puts a datum which
  64.  * overfills the buffer.  That bputo() causes the "get" side to believe that
  65.  * there is no data in the buffer.  However it can test the overrun flag
  66.  * with boverp() and report the error, then clear the flag with boverclr().
  67.  * bput(), bgetp(), and bget() do not set or check overrun.  The unimplemented
  68.  * bputm() would return FALSE and avoid putting the datum if overrun would
  69.  * occur; since nobody needs it I'm leaving it as an exercise for the first
  70.  * person who does.
  71.  *
  72.  * MODIFIERS NOTE: exactly when each of getptr and putptr wrap from the
  73.  * end to the beginning is VITAL.  
  74.  *
  75.  * When putting data, putptr wraps just before placing some data in the buffer.
  76.  *
  77.  * When getting data, getptr wraps AFTER we have determined that
  78.  * at least one datum exists in the buffer, but BEFORE we reference that
  79.  * datum.  This is because, if we wrapped it first thing, putptr might
  80.  * still be un-wrapped, and we'd think we had a whole bufferfull of data.
  81.  *
  82.  * MODIFIERS ALSO NOTE: great pain was taken to avoid referencing the 
  83.  * "other" pointer more than once in a get or put.  This avoids problems
  84.  * when interrupt routines are updating the pointers (which is what
  85.  * these macros were designed for).  NO macros set the other guy's pointer.
  86.  *
  87.  */
  88.  
  89. #ifndef DEFBUF
  90.  
  91. /* This macro defines a buffer type of your choice.  Parameters are the
  92.    name of the buffer structure, type of element, and number of elements.
  93.  *
  94.  */
  95. #define    DEFBUF(NAME,TYPE,HOWMANY) \
  96. struct NAME { \
  97.     TYPE *    getptr; \
  98.     TYPE *    putptr; \
  99.     TYPE *    endptr;        /* always contains &blocks[HOWMANY] */ \
  100.     char    overrun;    /* set TRUE when an overrun occurs */ \
  101.     TYPE    block [HOWMANY]; \
  102. };
  103.  
  104. /*
  105.  * Initialize a buffer before its first use.  Parameters are buffer name
  106.  * and number of elements.
  107.  */
  108. #define    initbuf(buffer, HOWMANY) \
  109.     { \
  110.     (buffer)-> getptr = (buffer)-> putptr = &(buffer)-> block[0]; \
  111.     (buffer)-> endptr = &(buffer)-> block[HOWMANY]; \
  112.     (buffer)-> overrun = 0; \
  113.     }
  114.     
  115.  
  116. /*
  117.  * bputo (buffer, datum);    puts datum into buffer, setting overrun
  118.  *                if reader is too far behind.
  119.  * bputm (buffer, datum)    puts datum into buffer if there's room,
  120.  *    ^^unimplemented^^    returning FALSE; else returns TRUE.
  121.  * bput  (buffer, datum);    puts datum into buffer, ignoring overrun.
  122.  * bgetp (buffer)        returns TRUE if there is data to be read.
  123.  * bget  (buffer, datum)    returns the next datum.
  124.  * bgets (buffer, addr, count)    returns addr&count of contiguous data in buf
  125.  * baccs (buffer, count)    accepts count datums after using bgets
  126.  * bputclr (buffer)        clears the buffer -- for "put" task
  127.  * bgetclr (buffer)        clears the buffer -- for "get" task
  128.  * boverp (buffer)        returns TRUE if overrun is set
  129.  * boverclr (buffer)        clears overrun to FALSE
  130.  * bsize (buffer, count)    returns how many datums are there, in count
  131.  *
  132.  */
  133.  
  134. #define    bput(buffer, datum) \
  135.     { \
  136.     if ( (buffer)->putptr >= (buffer)->endptr ) \
  137.         (buffer)->putptr = &((buffer)->block[0]); \
  138.     ( * ( (buffer)->putptr )++ ) = datum; \
  139.     }
  140.  
  141. #define    bputo(buffer, datum) \
  142.     { \
  143.     bput(buffer, datum); \
  144.     if ( (buffer)->putptr == (buffer)->getptr ) \
  145.         (buffer)->overrun = 1; \
  146.     }
  147.  
  148. #define    bgetp(buffer) \
  149.     ( (buffer)->getptr != (buffer)->putptr )
  150. /* This depends on TRUE and FALSE being returned by != */
  151. /* If that doesn't work, use:
  152.   (    ( (buffer)->getptr != (buffer)->putptr ) ? 1 : 0   )
  153.                                     */    
  154.  
  155. #define    bget(buffer, datum) \
  156.     { \
  157.     if ( (buffer)->getptr >= (buffer)->endptr ) \
  158.         (buffer)->getptr = &(buffer)->block[0]; \
  159.         datum = *(buffer)->getptr++; \
  160.     }
  161.  
  162. #define    bgets(buffer, addr, count) \
  163.     { \
  164.     register unsigned char* putptr = (buffer)->putptr;\
  165.     /* This avoids double ref to (buffer)->putptr - it might change. */\
  166.     /* Note the above assumes datatype of buffer is "u char" - BUG */\
  167.     if ((buffer)->getptr > putptr) {\
  168.         /* Buffer has wrapped. See if we've gotten last chunk \
  169.            at end.  If so, go to front; otherwise treat endptr \
  170.            as if it was putptr, to return trailing chunk only. */\
  171.         if ( (buffer)->getptr >= (buffer)->endptr ) \
  172.             (buffer)->getptr = &(buffer)->block[0]; \
  173.         else                        \
  174.             putptr = (buffer)->endptr; \
  175.     } \
  176.     addr = (buffer)->getptr; \
  177.     count = putptr - (buffer)->getptr; \
  178.     }
  179.  
  180. #define    baccs(buffer, count) \
  181.     (buffer)->getptr += count
  182.  
  183. #define    bputclr(buffer) \
  184.     (buffer)->putptr = (buffer)->getptr
  185.  
  186. #define    bgetclr(buffer) \
  187.     (buffer)->getptr = (buffer)->putptr
  188.  
  189. #define    boverp(buffer) \
  190.     (0 != (buffer)->overrun)
  191.  
  192. #define    boverclr(buffer) \
  193.     (buffer)->overrun = 0
  194.  
  195. #define    bsize(buffer, count) \
  196.     { \
  197.     count = (buffer)->putptr - (buffer)->getptr; \
  198.     /* If putptr<getptr, adjust for wrap. */\
  199.     if ((int)count < 0) count += \
  200.         sizeof((buffer)->block) / sizeof((buffer)->block[0]); \
  201.     }
  202.  
  203. #endif DEFBUF
  204.